import  underScore    from  'underscore';
let     crypo         =require('crypto');
import  lorck         from 'lockr';
import  ajax          from 'jquery';
const   MD5_NAME      ='md5';
const   HEX_TYPE      ='hex';
const   SUCCESS_CODE  =1000;
const   ERROR_CODE    =1001;
import  { stackToken } from '../static/comm/commom'
class UploadAction {
  constructor() {

    //初始化当前的数组处理工具
    this.undererScore = underScore;
    //设置html5的对象读取
    this.fileReader   = null;
    //加密对象
    this.cryptoRender = crypo;
    //需要拖拽的dom节点
    this.uploaddom    = '';
    //当前上传的图片张数
    this.files        = [];
    //上传的设置
    this.option       = {};
    //vue对象存储
    this.context_vue  =null;
    //点击上传的按钮
    this.btndom       =null;
    //缓存读取
    this.lorck        = lorck;
    //书写进度条原生的xmlHttpRequest造成后台读取不到
    this.jquery       = ajax;
    //进度条的开始时间
    this.start_time   = 0;
    //进度条的结束时间
    this.end_time     = 0;
    //进度条的开端
    this.progressStart= 0;
    //遮罩的开始
    this.maskProgress = 100;
    //点击上传按钮
    this.click_upload =null;
    this.header       ={};
  }

  //设置上下文环境
  Context_set(option,vue_context) {
    try {

      //接收当前的dom对象
      //展开复制
      this.option       = {...option};
      //当前的vue的上下文环境
      this.context_vue  = vue_context;
      //获取当前的区域拖拽
      this.uploaddom    = this.context_vue.$refs.upload;
      if(!this.uploaddom)
      {
          this.option.dialogAction.call(null,'请设置拖拽区域');
          return false;
      }
      //获取点击上传的按钮
      this.btndom       = this.context_vue.$refs.upload_btn;
      if(!this.btndom)
      {
          this.option.dialogAction.call(null,'请设置当前的上传按钮');
          return false;
      }
      this.click_upload = this.context_vue.$refs.clickUp;
      if(!this.click_upload){
        this.option.dialogAction.call(null,'请设置当前的点击上传的按钮！');
        return false;
      }
      //设置当前的加载拖拽的事件
      this._all_actions_trigger();
    }catch (e){this.option.dialogAction.call(null,'上下文环境设置错误！');}
  }

  //触发所有的事件
  _all_actions_trigger() {
    try {
      //可以写成一个链式的调用 方便快捷
      this._dragEnter()._leave()._over_drag()._dragAction()._trigger_btn()._trigger_click();
    }catch (e){this.option.dialogAction.call(null,'抱歉当前的加载事件设置错误');}
  };

  //当前拖拽进入的时候
  _dragEnter() {
    //为他监听一拖拽进入的事件
    this.uploaddom.addEventListener('dragenter', e => {
      //禁止默认事件
      e.preventDefault();
    }, false);
    return this;
  }

  //当前拖拽离开此区域 触发
  _leave() {
    this.uploaddom.addEventListener('leave', e => {
      //禁止默认事件
      e.preventDefault();
    }, false);
    return this;
  }

  //拖拽完毕之后触发
  _over_drag()
  {
    console.log('dragover');
    this.uploaddom.addEventListener('dragover', e => {
      //禁止默认事件
      e.preventDefault();
    }, false);
    return this;
  }

  //在拖拽的时候进去鼠标放下的时候触发  //拖拽放置，也需要阻止默认行为
  _dragAction()
  {
    //drop鼠标放下的事件
    this.uploaddom.addEventListener('drop', e => {
      //禁止默认事件
      e.preventDefault(); // 阻止默认事件;
      let files = e.dataTransfer.files;//当前的上传的文件 拖拽时的上传的文件数目
      if (files.length === 0) {
        return false
      }
      this._getFiles(files);
    }, false);
    return this;
  }

  _getFiles(files)
  {
    /**
     * 通过引入的模块可以知道，digest() 是 crypto加密模块中的一个方法，API 的解释为计算传入的所有数据的摘要值，其参数是编码方式，可以有 'hex'、'binary'或者'base64'
     */
    let  is_send        = (files.length)-1;
    for (let i = 0; i < files.length; ++i) {
      let file  =  files[i],push_obj    = {};
      //如果不支持的话那么就直接不做上传处理或者改换浏览器或者升级浏览器
      // url = window.URL.createObjectURL(file); //获取本地文件的url，如果是图片文件，可用于预览图片
     if('function'!==typeof window.FileReader)
     {
       this.option.dialogAction.call(null,'抱歉请升级您的浏览器或更改浏览器之后再做上传！');
       return false
     }
      //实例化当前的H5的文件处理类
      this.fileReader = new FileReader();
      //读取当前的图片的地址  可以做图片的实时监控 利用  converse
      this.fileReader.readAsDataURL(file);
      //上传开始时回调
      this.fileReader.onloadstart = e => {
          //检查当前的上传大小
      };
      /**
       *
       * @param result
         FileList {0: File, length: 1}
         0:File
         lastModified:1501050786356
         lastModifiedDate:Wed Jul 26 2017 14:33:06 GMT+0800 (中国标准时间)
         name:"微信图片_20170726143303.jpg"
         size:67403
         type:"image/jpeg"
         webkitRelativePath:""
       */
      //上传完了回调
      this.fileReader.onload =  e => {
         let upload_ctx      =  e.target.result;

      };
      //上传过程中回调
      this.fileReader.onprogress  = e => {
        //判断当前的进度条信息是否可用
        if(true===e.lengthComputable)
        {
          //已经读取了多少文件信息
          let loaded_size          = e.loaded;
          //上传时图片的大小 可研究断点续传  加上当前的上传进度条
          let upload_size          = e.total;
          let upload_computable    = Math.round(loaded_size/upload_size)*100;
          //转换成字符串以显示当前的上传的进度 读取的进度条而不是上传的精度条
          let progress_text        = upload_computable.toString()
          //获得当期显示精度条的一个dom节点;
        }
        return true;
      };
      //上传结束时回调
      this.fileReader.onloadend = e => {
        //当前的图片的二进制流 或者说是base64的加密码
        let ctx               = e.target.result;
        let DES               = this.cryptoRender.createHash(MD5_NAME);
        DES.update(ctx);
        //生成md5值去做唯一性的判断
        let hashPassword      =  DES.digest(HEX_TYPE);
        //大于等于零以为存在不在做上传的操作
        if(this.undererScore.findIndex(this.files,{hash_val:hashPassword})>=0)
        {
          //也可以不用call去唤醒当前方法直接调用就可以了
          this.option.dialogAction.call(null,'抱歉你当前添加的图片已经上传再次不在做上传！');
          return false;
        }
        //加上is_uploaded判读是否已经做过上传的操作  如果当前已经做过上传操作那么不在显示当前的上传按钮！
        push_obj.hash_val      = hashPassword;  push_obj.name   = file.name; push_obj.is_uploaded=false;
        //这是为了当前的显示进度条
        push_obj.fileObj       = file;          push_obj.imgUri = ctx; push_obj.is_show     =false; push_obj.percent='100%';
        push_obj.percent_text  = '0%';
        //>>当前已经上传的加载内存当中以便以便下次做判断 刷新页面会做从新的判断
        this.files.push(push_obj);
        //最后一次在调用改方法
        if(is_send===i) {
          this.option.complete.call(null, this.files,'已加载完毕');
        }
      };
      //上传错误时候回调
      this.fileReader.onerror = error => {
              this.option.errorHandler.call(null,error,'抱歉当前的上传错误');
      }
    }
  }
  //当前的触发当前上传的按钮已开始上传
  _trigger_btn()
  {
    //为上传按添加点击事件
    this.btndom.addEventListener('click',()=>{
      //prepare upload on service
       this._upload_service();
    },false);
    return this;
  }


  _trigger_click(){
    this.click_upload.addEventListener('click',(e)=>{
      let InputDom      = document.createElement('input');
          InputDom.type ='file';
          InputDom.accept='Image/*';
          InputDom.name  =this.option.uploadName;
          //添加当前的上传元素的名称
          InputDom.addEventListener('change',(e)=>{
            console.log(e);
            if(InputDom.files.length===0){return false;}
            this._getFiles(InputDom.files);
          },false);
          //自动触发点击事件
          InputDom.click();
    });
  }


  _upload_service(){
    try {
      //判断当前的上传文件是否为空
      if (0 === this.files.length) {
         throw '抱歉你没有选择任何图片上传';
      }
      //已上传的会改变状态
      let tmp_files = this.undererScore.where(this.files, {is_uploaded: false});
      if (0 === tmp_files.length) {
         throw   '当前没有可上传的图片！';
      }
      //当前的ajax请求对象
      let sendResult = this._requestGet();
      sendResult.then((response)=>{

      }).cache((error_response)=>{

      })
    }catch (errorMsg){
      this.option.dialogAction.call(null, errorMsg);
    }

  }

  //获取request对象也可以用axios 但是为了显示进度条我们这里使用原生的ajax
  _requestGet()
  {

    try {
      //返回一个promise对象
      return new Promise((solve,reject)=>{
         /*   let    requestObj;
            if(window.XMLHttpRequest){
              requestObj    = new XMLHttpRequest();
            }else if(window.ActiveXObject){
              requestObj    = new ActiveXObject();
            }else {
              throw  '抱歉您当前的浏览器不支持异步上传';
            }*/
            //构建当前的请求头数据
            this.files.forEach((item,index)=>{
                  //构建当前的表单数据 和精度条的时间
                  let form_data           = new FormData();
                  //开始上传的时间 第一次读取的时间
                  this.start_time       = new Date().getTime();
                  //驱动当前的dom改变 点击时开启当前上传的指示遮罩
                  this.context_vue.$nextTick(()=>{
                    this.context_vue.$set(this.context_vue.files[index],'is_send',true);
                  });
                  form_data.append(this.option.uploadName,item.fileObj);
                  form_data.append('hash_val',item.hash_val);
                  form_data.append('upload_name',this.option.uploadName);
                  //>>设置当前的请求的授权key
                  let authKey                 = JSON.parse(this.lorck.get('authKey'));
                  //>>和会话id
                  let sessionId               = JSON.parse(this.lorck.get('sessionId'));
                  //>>ajax不支持当前的header对象fetch api可以支持
                  let header          ={
                    'authkey':authKey.data,
                    'sessionId':sessionId.data
                  };
                  this.header         =Object.assign(this.header,header);
                  let ajax_option     ={
                    url:this.option.uploadUri,
                    type:'POST',
                    data:form_data,
                    headers:header,
                    xhr:(e)=>{
                      //得到jquery的xhr对对象里面是否有upload属性
                      let myXhr               = this.jquery.ajaxSettings.xhr();
                      //判断当前的是否存在upload对象
                      let requestObj          = myXhr.upload;
                      if(!requestObj){
                        this.option.dialogAction.call(null,'抱歉异步上传组件不支持该浏览器！');
                        return false;
                      }
                      //注册上传的给个事件 下面采取es6的箭头函数的目的是为了不产生其他函数的作用域影响全局的调用;
                      requestObj.onloadstart  =e=>{this._uploadStart(e);};
                      requestObj.onprogress   =e=>{this._uploadProgress(e,index);};
                      requestObj.onload       =e=>{this._uploadLoad(e,index);};
                      requestObj.onerror      =e=>{this._uploadError(e);};
                      //xhr对象返回给jQuery使用 不返回是不会发送请求的
                      //返回一个对象里面说没有发现open的属性
                      // Object {readyState: 0, status: 0, statusText: "TypeError: Cannot read property 'open' of undefined"}
                      return myXhr;
                    },
                    success:(response,status,xhr)=>{  //成功时的响应函数
                      console.log(response);
                    if('success'!==status.toLocaleLowerCase() || ERROR_CODE===response.status){return false;}
                    let responseAuth        = xhr.getResponseHeader('authKey');
                    let responseSession     = xhr.getResponseHeader('sessionID');
                    if(!responseAuth || !responseSession){return false}
                    let responseHeaders     = Object.assign({},{headers:{authkey:responseAuth,sessionid:responseSession}});
                    console.log(responseHeaders);
                    stackToken(responseHeaders);
                    this.context_vue.$set(this.context_vue.files[index],'percent','100%');
                    },
                    error:(error)=>{
                      //>>上传失败设置当前的sessionId 和 当前的authKey
                      let responseAuth        = error.getResponseHeader('authKey');
                      let responseSession     = error.getResponseHeader('sessionID');
                      if(!responseAuth || !responseSession){return false}
                      let responseHeaders     = Object.assign({},{headers:{authkey:responseAuth,sessionid:responseSession}});
                      stackToken(responseHeaders);
                    },
                    contentType:false,  //设置为false那么才能避免当前不设置content-type选线
                    processData:false,   //设置为false才能避开jquery对当前的formData中的数据做处理
                  };
                  this.jquery.ajax(ajax_option);
               });
      })
    } catch (errorMsg){
          this.option.dialogAction.call(null,errorMsg);
    }
  }

  //上传进度方法
  _uploadProgress(e,index){
    if(false===e.lengthComputable){
         return false
    }
    //当前结束时间
    this.end_time   = new Date().getTime();
    //计算当前的时间差
    let result_time = this.calculationTime();
    //计算完之后那么上一次的时间就是下一段上传开始的时间
    this.start_time = this.end_time;
    //当前已经上传的字节数
    let loaded      = e.loaded;
    //文件的总大小数
    let total       = e.total;
    //上传的进度条
    let percent_text= (Math.round(loaded*100/total));
    //上传的百分比
    let percent     = (100-percent_text);
    //只触发一次
    let Interval    = setInterval((e)=>{
          //判断进度条的状况先判断进度条的是否已经加到页当前的百分比
          if(this.progressStart===percent_text || this.maskProgress===percent){
            clearInterval(Interval);
          }
          //触发当前的dom结构发生改变。。数据驱动dom  做一个缓慢的下降的进度条
          this.progressStart++;this.maskProgress--;
          if(this.progressStart>100){this.progressStart=100;clearInterval(Interval);}
          if(this.maskProgress<0){this.maskProgress=0;clearInterval(Interval);}
          let displayStart    = this.progressStart,maskProgress    = this.maskProgress;
          this.context_vue.$nextTick(()=>{
            this.context_vue.$set(this.context_vue.files[index],'percent',maskProgress.toString()+'%');
            this.context_vue.$set(this.context_vue.files[index],'percent_text',displayStart.toString()+'%');
          });
        },50); //第二个参数是多少毫秒执行一次  第三个参数是传到后调函数的参数
  }
  //加载完毕之后在回调此函数
  _uploadLoad(e,index){

  }
  //上传错误回调函数
  _uploadError(e){
    console.debug('uploadError');
  }
  //上传开始回调函数
  _uploadStart(e){
     console.log(this.maskProgress,this.progressStart);
  }

  //计算当前的时间已以便设置计时器的时间
  calculationTime()
  {
    return (this.end_time-this.start_time)*10;
  }

}
//导出上传类
export default UploadAction;
